/*----------------------------------------------------------------------------------------
*
*  Copyright 2019, Gao Hai Hui, <fromzeropoint@126.com>.  All rights reserved.
*  https://gitee.com/helloworldghh/xos_http.git
*  Use of this source code is governed by a MIT license
*  that can be found in the License file.
*
----------------------------------------------------------------------------------------*/
#include "../import/head.h"
#include "../data_struct/head.h"
#include "../helper_objs/head.h"
#include "../config/head.h"
#include "../macro/head.h"
#include "../impl/head.h"
#include "../msg/head.h"
#include "notify_udp.h"
#include "msg_notify.h"

namespace xos_http
{

    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    notify_udp::notify_udp()
    {
    }

    notify_udp::~notify_udp()
    {
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    // bool[0]      : if success
    // 
    // msg[0]       : msg type
    // 
    // str[1]       : local ip
    // int[1]       : local port
    // 
    // void[0]      : net::i_connection*
    // void[1]      : user data
    // 
    int notify_udp::post_init_server( xos_box::i_msg *& pMsg, connection * pConnect )
    {
        int ret = 0;

        if( !pMsg )
        {
            pMsg = mgr::container()->box()->msg();
        }

        if( 0 == ret )
        {
            pMsg->set_str( 1, pConnect->get_local_ip(0,0,0) );
            pMsg->set_int( 1, pConnect->get_local_port(0) );
            pMsg->set_msg( 0, net::NET_UDP_INIT_SERVER );
            pMsg->set_void( 1, pConnect->xos_connect() );
        }

        if( 0 == ret )
        {
            helper_net_callback::get()->notify( pMsg );
        }

        xos_stl::release_interface( pMsg );

        return ret;
    }

    // bool[0]      : if success
    // 
    // bool[1]      : close after send
    // bool[2]      : quit after send
    // 
    // msg[0]       : msg type
    // 
    // str[2]       : peer ip
    // int[2]       : peer port
    // 
    // int[0]       : bytes
    // buf[0]       : buf
    // 
    // void[0]      : net::i_connection*
    // 
    int notify_udp::post_send( xos_box::i_msg *& pMsg, connection * pConnect, const char * lpszIp, int nPort, const char * lpszData, bool bCloseAfterSend, bool bQuitAfterSend )
    {
        int ret = 0;

        int nLen = mgr::container()->crt()->strlen( lpszData );

        if( 0 == ret )
        {
            ret = post_send( pMsg, pConnect, lpszIp, nPort, lpszData, nLen, bCloseAfterSend, bQuitAfterSend );
        }

        return ret;
    }

    // bool[0]      : if success
    // 
    // bool[1]      : close after send
    // bool[2]      : quit after send
    // 
    // msg[0]       : msg type
    // 
    // str[2]       : peer ip
    // int[2]       : peer port
    // 
    // int[0]       : bytes
    // buf[0]       : buf
    // 
    // void[0]      : net::i_connection*
    // 
    int notify_udp::post_send( xos_box::i_msg *& pMsg, connection * pConnect, const char * lpszIp, int nPort, const char * lpszData, int nLen, bool bCloseAfterSend, bool bQuitAfterSend )
    {
        int ret = 0;

        xos_box::i_buf * pBuf = mgr::container()->box()->buf();

        if( 0 == ret )
        {
            pBuf->add_data( lpszData, nLen, true );
            ret = post_send( pMsg, pConnect, lpszIp, nPort, pBuf, bCloseAfterSend, bQuitAfterSend );
            pBuf = 0;
        }

        xos_stl::release_interface( pBuf );

        return ret;
    }

    // bool[0]      : if success
    // 
    // bool[1]      : close after send
    // bool[2]      : quit after send
    // 
    // msg[0]       : msg type
    // 
    // str[2]       : peer ip
    // int[2]       : peer port
    // 
    // int[0]       : bytes
    // buf[0]       : buf
    // 
    // void[0]      : net::i_connection*
    // 
    int notify_udp::post_send( xos_box::i_msg *& pMsg, connection * pConnect, const char * lpszIp, int nPort, xos_box::i_buf * pBuf, bool bCloseAfterSend, bool bQuitAfterSend )
    {
        int ret = 0;

        net::i_connect * pNetConnect = pConnect->get_net_connect();
        if( !pMsg )
        {
            pMsg = mgr::container()->box()->msg();
        }

        if( 0 == ret )
        {
            pMsg->set_bool( 1, bCloseAfterSend );
            pMsg->set_bool( 2, bQuitAfterSend );
            pMsg->set_msg( 0, net::NET_UDP_SEND );
            pMsg->set_str( 2, lpszIp );
            pMsg->set_int( 2, nPort );
            pMsg->set_buf( 0, pBuf );
        }

        if( 0 == ret )
        {
            pMsg->set_void( 0, pNetConnect );
        }

        if( 0 == ret )
        {
            pNetConnect->add_ref();
            helper_net_callback::get()->notify( pMsg );
        }

        xos_stl::release_interface( pMsg );

        return ret;
    }

    // bool[0]      : if success
    // 
    // msg[0]       : msg type
    // 
    // int[0]       : how
    // 
    // void[0]      : net::i_connection*
    // 
    int notify_udp::post_shutdown( xos_box::i_msg *& pMsg, connection * pConnect, int how )
    {
        int ret = 0;

        net::i_connect * pNetConnect = pConnect->get_net_connect();
        if( !pMsg )
        {
            pMsg = mgr::container()->box()->msg();
        }

        if( 0 == ret )
        {
            pMsg->set_msg( 0, net::NET_UDP_SHUTDOWN );
            pMsg->set_void( 0, pNetConnect );
            pMsg->set_int( 0, how );
            pNetConnect->add_ref();
            helper_net_callback::get()->notify( pMsg );
        }

        xos_stl::release_interface( pMsg );

        return ret;
    }

    // bool[0]      : if success
    // 
    // msg[0]       : msg type
    // 
    // void[0]      : net::i_connection*
    // 
    int notify_udp::post_close( xos_box::i_msg *& pMsg, connection * pConnect )
    {
        int ret = 0;

        net::i_connect * pNetConnect = pConnect->get_net_connect();
        if( !pMsg )
        {
            pMsg = mgr::container()->box()->msg();
        }

        if( 0 == ret )
        {
            pMsg->set_msg( 0, net::NET_UDP_CLOSE );
            pMsg->set_void( 0, pNetConnect );
            pNetConnect->add_ref();
            helper_net_callback::get()->notify( pMsg );
        }

        xos_stl::release_interface( pMsg );

        return ret;
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    // 
    // proc
    // 
    int notify_udp::proc( xos_box::i_msg*& pMsg )
    {
        int ret = 1;

        int nMsg = pMsg->get_msg();

        switch( nMsg )
        {
            case net::NET_UDP_INIT_SERVER:
            {
                on_init_server( pMsg );
            }
            break;
            case net::NET_UDP_SEND:
            {
                on_send( pMsg );
            }
            break;
            case net::NET_UDP_RECV:
            {
                on_recv( pMsg );
            }
            break;
            case net::NET_UDP_SHUTDOWN:
            {
                on_shutdown( pMsg );
            }
            break;
            case net::NET_UDP_CLOSE:
            {
                on_close( pMsg );
            }
            break;

            default:
            {
                ret = 0;
            }
            break;
        }

        return ret;
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    // bool[0]      : if success
    // 
    // msg[0]       : msg type
    // 
    // m_nData[1]   : local port
    // m_szStr[1]   : local ip
    // 
    // str[1]       : local ip
    // int[1]       : local port
    // 
    // void[0]      : xos_http::connection*
    // void[1]      : user data
    // 
    int notify_udp::on_init_server( xos_box::i_msg*& pMsg )
    {
        int ret = 0;

        net::i_connect * pNetConnect = (net::i_connect *)pMsg->get_void( 0, 0 );
        connection * pConnect = (connection *)pNetConnect->get_user_data();

        bool bRet = pMsg->get_bool( 0, 0 );

        // 稍后xos_net会回调on_release来释放这里的connection
        // 所以这里不要释放这个connection
        if( ( 0 == ret ) && !bRet )
        {
            pNetConnect->release_ref();
            ret = 1;
        }

        if( 0 == ret )
        {
            const char * lpszLocalIp = pMsg->get_str( 1, 0, 0, 0 );
            int nLocalPort = pMsg->get_int( 1, 0 );
            LOG4( "init udp server (%s:%d)", lpszLocalIp, nLocalPort );
            pConnect->set_local_addr( lpszLocalIp, nLocalPort );
            pConnect->set_net_connect( pNetConnect );
        }

        pNetConnect->release_ref();

        return ret;
    }

    // bool[0]      : if success
    // 
    // bool[1]      : close after send
    // bool[2]      : quit after send
    // 
    // msg[0]       : msg type
    // 
    // m_nData[2]   : peer port
    // m_szStr[2]   : peer ip
    // 
    // int[0]       : bytes
    // buf[0]       : buf
    // 
    // void[0]      : xos_http::connection*
    // 
    int notify_udp::on_send( xos_box::i_msg*& pMsg )
    {
        int ret = 0;

        net::i_connect * pNetConnect = (net::i_connect *)pMsg->get_void( 0, 0 );
        connection * pConnect = (connection *)pNetConnect->get_user_data();

        xos_box::i_buf * pBuf = pMsg->get_buf( 0, 0 );
        int nLen = pMsg->get_int( 0, 0 );

        bool bCloseAfterSend = pMsg->get_bool( 1, 0 );
        bool bQuitAfterSend = pMsg->get_bool( 2, 0 );

        bool bRet = pMsg->get_bool( 0, 0 );

        if( ( 0 == ret ) && !bRet )
        {
            ret = 1;
        }

        if( 0 == ret )
        {
            const char * lpszPeerIp = pMsg->get_str( 2, 0, 0, 0 );
            int nPeerPort = pMsg->get_int( 2, 0 );
            const char * lpszLocalIp = 0;
            int nLocalPort = 0;
            lpszLocalIp = pConnect->get_local_ip(0,0,0);
            nLocalPort = pConnect->get_local_port(0);
            LOG4( "udp send local = (%s:%d), peer = (%s:%d), len = %d", lpszLocalIp, nLocalPort, lpszPeerIp, nPeerPort, nLen );
        }

        if( ( 0 == ret ) && bCloseAfterSend )
        {
            LOG4( "udp recv close after send" );
            post_close( pMsg, pConnect );
        }

        if( ( 0 == ret ) && bQuitAfterSend )
        {
            LOG4( "udp recv quit after send" );
            helper_caller_callback::get()->notify( pMsg, net::NET_QUIT );
        }

        xos_stl::release_interface( pBuf );
        pNetConnect->release_ref();

        return ret;
    }

    // bool[0]      : if success
    // 
    // msg[0]       : msg type
    // 
    // m_nData[2]   : peer port
    // m_szStr[2]   : peer ip
    // 
    // int[0]       : bytes
    // buf[0]       : buf
    // 
    // void[0]      : xos_http::connection*
    // 
    int notify_udp::on_recv( xos_box::i_msg*& pMsg )
    {
        int ret = 0;

        net::i_connect * pNetConnect = (net::i_connect *)pMsg->get_void( 0, 0 );
        connection * pConnect = (connection *)pNetConnect->get_user_data();

        const char * lpszPeerIp = pMsg->get_str( 2, 0, 0, 0 );
        int nPeerPort = pMsg->get_int( 2, 0 );

        xos_box::i_buf * pBuf = pMsg->get_buf( 0, 0 );
        int nLen = pMsg->get_int( 0, 0 );

        {
            const char * lpszLocalIp = pConnect->get_local_ip( 0, 0, 0 );
            int nLocalPort = pConnect->get_local_port( 0 );
            LOG4( "udp recv local = (%s:%d), peer = (%s:%d), len = %d", lpszLocalIp, nLocalPort, lpszPeerIp, nPeerPort, nLen );
        }

        xos_stl::release_interface( pBuf );
        pNetConnect->release_ref();

        return ret;
    }

    // bool[0]      : if success
    // 
    // msg[0]       : msg type
    // 
    // void[0]      : xos_http::connection*
    // 
    int notify_udp::on_shutdown( xos_box::i_msg*& pMsg )
    {
        int ret = 0;

        net::i_connect * pNetConnect = (net::i_connect *)pMsg->get_void( 0, 0 );
        connection * pConnect = (connection *)pNetConnect->get_user_data();

        if( 0 == ret )
        {
            const char * lpszLocalIp = pConnect->get_local_ip( 0, 0, 0 );
            int nLocalPort = pConnect->get_local_port( 0 );
            LOG4( "udp shutdown = (%s:%d)", lpszLocalIp, nLocalPort );
        }

        pNetConnect->release_ref();

        return ret;
    }

    // bool[0]      : if success
    // 
    // msg[0]       : msg type
    // 
    // void[0]      : xos_http::connection*
    // 
    int notify_udp::on_close( xos_box::i_msg*& pMsg )
    {
        int ret = 0;

        net::i_connect * pNetConnect = (net::i_connect *)pMsg->get_void( 0, 0 );
        connection * pConnect = (connection *)pNetConnect->get_user_data();

        if( 0 == ret )
        {
            const char * lpszLocalIp = pConnect->get_local_ip( 0, 0, 0 );
            int nLocalPort = pConnect->get_local_port( 0 );
            LOG4( "udp close = (%s:%d)", lpszLocalIp, nLocalPort );
        }

        pNetConnect->release_ref();

        return ret;
    }

} // xos_http
